<template>
  <div
    :style="{
      width: store.screenConfig.width * store.screenConfig.scale + 'px',
      height: store.screenConfig.height * store.screenConfig.scale + 'px',
    }"
  >
    <div
      id="canvas"
      @drop="drop"
      @dragover="allowDrop"
      @mousemove="moveWidget"
      @mouseup="stopMove"
      @mouseleave="stopMove"
      @click="selectScreen"
      :style="screenConfig"
    >
      <canvas
        id="canvas-grid"
        :width="store.screenConfig.width"
        :height="store.screenConfig.height"
      ></canvas>
      <widget
        class="widget-component"
        :class="{ hover: hoverUUID === (widget.uuid || 'none_id') }"
        :data-uuid="widget.uuid"
        :uuid="widget.uuid"
        @mousedown="widgetMoveStart($event, widget.uuid)"
        @mouseup="stopMove"
        @click="selectWidget($event, widget.uuid)"
        v-for="widget in widgetList"
        :widgetName="widget.widget"
      >
        <GRStransition :widget="widget" />
      </widget>
      <canvas
        id="draw-area"
        :width="store.screenConfig.width"
        :height="store.screenConfig.height"
      ></canvas>
    </div>
  </div>
</template>

<script lang="ts">
import draggable from "vuedraggable";
import widget from "@/widgets/index.vue";
import GRStransition from "./transition.vue";
import {
  defineComponent,
  computed,
  ComputedRef,
  ref,
  reactive,
  onMounted,
  nextTick,
  watch,
} from "vue";
import { useStore } from "@/store/index";
import { findWidgetByName, screenGlobalConfig } from "@/config/index";
import { uuid, attachListener } from "@/utils/utils";
import { getDefaultValue, getScreenDefaultValue } from "@/utils/config";

export default defineComponent({
  components: {
    draggable,
    widget,
    GRStransition,
  },
  setup(_, { emit }) {
    const store = useStore();
    const widgetList: ComputedRef<widgetConfig[]> = computed<widgetConfig[]>(
      () => store.widgetList
    );
    const targetElement = ref<any>();
    const isMove = ref<boolean>(false);
    const hoverUUID = ref<string>("");
    const canvasCtx = ref<any>();
    const position = reactive({
      x: 0,
      y: 0,
    });
    onMounted(() => {
      nextTick(() => {
        const target = document.getElementById("canvas");
        position.x = target?.offsetLeft || 0;
        position.y = target?.offsetTop || 0;
        const drawArea = <HTMLCanvasElement>(
          document.getElementById("draw-area")
        );
        if (drawArea) {
          canvasCtx.value = drawArea.getContext("2d");
          store.commit("SET_CTX", canvasCtx.value);
        }
        // 添加delete按钮的监听事件
        window.addEventListener("keydown", (event) => {
          if (
            !(event.target instanceof HTMLElement) ||
            event.target.nodeName !== "BODY"
          )
            return;
          if (event.key === "Delete" || event.key === "Backspace") {
            store.commit("REMOVE_WIDGET", store.uuid);
          }
        });
        drawGrid();
      });
      getScreenDefaultValue(screenGlobalConfig, store);
    });
    const drop = (event: DragEvent) => {
      event.preventDefault();
      const files = event.dataTransfer?.files;
      let widgetName = event.dataTransfer?.getData("widget-code");
      // 查看是否存在图片文件
      let hasImage = false;
      if (files && files.length > 0) {
        for (let i = 0; i < files.length; i++) {
          if (files[i].type.includes("image")) {
            hasImage = true;
            break;
          }
        }
      }
      if (!widgetName && !hasImage) return;
      if (!widgetName) {
        widgetName = "imageComponent";
      }
      const widget: widgetConfig = { ...findWidgetByName(widgetName || "") };
      widget.uuid = uuid();
      store.commit("ADD_WIDGET", widget);
      getDefaultValue(widget, store);
      emit("showForm", widget);
      let { x, y } = event;
      const { scale } = store.screenConfig;
      x = (x - position.x) / scale + position.x;
      y = (y - position.y) / scale + position.y;
      const { width, height } = store.widgetConfig[widget.uuid];
      store.commit("SET_WIDGET_CONFIG", {
        uuid: widget.uuid,
        propsName: "left",
        value: x - position.x - width / 2,
      });
      store.commit("SET_WIDGET_CONFIG", {
        uuid: widget.uuid,
        propsName: "top",
        value: y - position.y - height / 2,
      });
      if (hasImage) {
        const reader = new FileReader();
        reader.onload = (e) => {
          store.commit("SET_WIDGET_CONFIG", {
            uuid: widget.uuid,
            propsName: "backgroundImage",
            value: e.target?.result,
          });
        };
        reader.readAsDataURL(files![0]);
      }
      event.dataTransfer?.setData("widget-code", "");
      event.preventDefault();
    };
    const allowDrop = (event: DragEvent) => {
      event.preventDefault();
    };
    const widgetMoveStart = (event: any, uuid: string | undefined) => {
      if (!event.target.className.includes("widget")) return;
      targetElement.value = event.target;
      isMove.value = true;
      hoverUUID.value = uuid || "";
      const target = document.getElementById("canvas");
      position.x = target?.offsetLeft || 0;
      position.y = target?.offsetTop || 0;
    };
    const moveWidget = (event: MouseEvent) => {
      if (!isMove.value) return;
      let { x, y } = event;
      // 计算画布的滚动距离
      const drawCanvas = document.getElementById("designer-parent");
      if (drawCanvas) {
        x += drawCanvas.scrollLeft;
        y += drawCanvas.scrollTop;
      }
      const { scale } = store.screenConfig;
      x = (x - position.x) / scale + position.x;
      y = (y - position.y) / scale + position.y;
      event.preventDefault();
      if (targetElement.value) {
        store.commit("SET_WIDGET_CONFIG", {
          uuid: targetElement.value.dataset.uuid,
          propsName: "left",
          value: x - position.x - targetElement.value.clientWidth / 2,
        });
        store.commit("SET_WIDGET_CONFIG", {
          uuid: targetElement.value.dataset.uuid,
          propsName: "top",
          value: y - position.y - targetElement.value.clientHeight / 2,
        });
      }
      attachListener();
    };
    const stopMove = (event: MouseEvent) => {
      isMove.value = false;
      canvasCtx.value.clearRect(
        0,
        0,
        store.screenConfig.width,
        store.screenConfig.height
      );
    };
    const selectWidget = (event: any, uuid: string | undefined) => {
      hoverUUID.value = uuid || "";
      event.stopPropagation();
    };
    const selectScreen = () => {
      hoverUUID.value = "";
    };
    watch(hoverUUID, (value) => {
      store.commit("SET_UUID", value);
    });
    const screenConfig: ComputedRef<any> = computed<any>(() => {
      // 计算缩放属性
      const { width, height, scale } = store.screenConfig;
      return {
        backgroundColor: store.screenConfig.backgroundColor,
        width: width + "px",
        height: height + "px",
        transformOrigin: "left top",
        transform: `scale(${scale})`,
      };
    });

    function drawGrid() {
      const { width, height, scale } = store.screenConfig;
      const drawGridElm = <HTMLCanvasElement>(
        document.getElementById("canvas-grid")
      );
      if (!drawGridElm) return;
      const ctx = drawGridElm.getContext("2d");
      if (!ctx) return;
      ctx.clearRect(0, 0, width, height);
      ctx.strokeStyle = "rgba(100, 100, 100, 0.5)";
      ctx.lineWidth = 1;
      ctx.beginPath();
      for (let i = 0; i < width; i += 20 * scale) {
        ctx.moveTo(i, 0);
        ctx.lineTo(i, height);
      }
      for (let i = 0; i < height; i += 20 * scale) {
        ctx.moveTo(0, i);
        ctx.lineTo(width, i);
      }
      ctx.stroke();
    }

    return {
      store,
      hoverUUID,
      widgetList,
      drop,
      allowDrop,
      moveWidget,
      stopMove,
      selectWidget,
      selectScreen,
      widgetMoveStart,
      screenConfig,
    };
  },
});
</script>

<style lang="less">
#canvas {
  height: 100%;
  width: 100%;
  overflow: hidden;
  position: relative;
  .widget-component {
    position: absolute;
    cursor: move;
  }
  .hover {
    z-index: 1000;
    border: 1px dashed #6688ee;
    .anchor {
      display: block;
    }
  }
  .anchor {
    z-index: 1000;
    display: none;
    position: absolute;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background-color: #3366ff;
  }
  .anchor-left-top {
    left: -5px;
    top: -5px;
    cursor: nwse-resize;
  }
  .anchor-right-top {
    right: -5px;
    top: -5px;
    cursor: nesw-resize;
  }
  .anchor-top {
    top: -5px;
    left: 50%;
    transform: translateX(-50%);
    cursor: ns-resize;
  }
  .anchor-left-bottom {
    left: -5px;
    bottom: -5px;
    cursor: nesw-resize;
  }
  .anchor-bottom {
    bottom: -5px;
    left: 50%;
    transform: translateX(-50%);
    cursor: ns-resize;
  }
  .anchor-right-bottom {
    bottom: -5px;
    right: -5px;
    cursor: nwse-resize;
  }
  .anchor-left {
    left: -5px;
    top: 50%;
    transform: translateY(-50%);
    cursor: ew-resize;
  }
  .anchor-right {
    right: -5px;
    top: 50%;
    transform: translateY(-50%);
    cursor: ew-resize;
  }
}
#draw-area {
  position: absolute;
  left: 0;
  top: 0;
  pointer-events: none;
}
#canvas-grid {
  position: absolute;
  left: 0;
  top: 0;
  pointer-events: none;
}
</style>
